﻿package com.qianfeng.day22_lrucache;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.util.LruCache;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends Activity {
	ImageView iv;
	MyLruCache myLruCache;
	// 定义所有存放SoftReference引用的Map
	Map<String, SoftReference<Bitmap>> map;
	String urlPath = "http://c.hiphotos.baidu.com/image/pic/item/5366d0160924ab18dd54473737fae6cd7b890b6b.jpg";
	Handler handler = new Handler() {
		@Override
		public void handleMessage(android.os.Message msg) {
			if (msg.what == 0) {
				Bitmap bm = (Bitmap) msg.obj;
				iv.setImageBitmap(bm);
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		iv = (ImageView) findViewById(R.id.iv);
		// 由次序的存放key-value的Map
		map = new LinkedHashMap<String, SoftReference<Bitmap>>();
		// 获取当前可用的内存空间
		long memorySize = Runtime.getRuntime().maxMemory();
		Log.i("123", "memorySize:" + memorySize);
		// 自己定义cache的内存大小(不要太大也不要太小)
		int cacheSize = (int) (memorySize / 8);
		Log.i("123", "cacheSize:" + cacheSize);
		myLruCache = new MyLruCache(cacheSize);

	}

	// LruCache的key就是图片的url地址，value就是实际存放的Bitmap
	public class MyLruCache extends LruCache<String, Bitmap> {
		// 构造方法传递设定的内存大小
		public MyLruCache(int maxSize) {
			super(maxSize);
			// TODO Auto-generated constructor stub
		}

		// 返回实际图片的大小(单位B)
		@Override
		protected int sizeOf(String key, Bitmap value) {
			// TODO Auto-generated method stub
			int size = value.getWidth() * value.getHeight() * 4;
			int size2 = value.getByteCount();
			return size;
		}

		// 置换算法的逻辑
		@Override
		protected void entryRemoved(boolean evicted, String key,
				Bitmap oldValue, Bitmap newValue) {
			// TODO Auto-generated method stub
			// evicted为true表示里面的oldValue过期了
			if (evicted) {
				// 软引用的对象可能会被系统回收
				SoftReference<Bitmap> soft = new SoftReference<Bitmap>(oldValue);
				// key就是url,value就是SoftReference
				map.put(key, soft);
			}
			super.entryRemoved(evicted, key, oldValue, newValue);
		}
	}

	/**
	 * 先从内存里查看是否存在需要的图片,有直接获取显示 如果内存中没有从网上去下载，下载完毕后存放到内存中
	 * 
	 * @param v
	 */
	public void btnClick(View v) {
		Bitmap bm = getBitmapFromCache(urlPath);
		if (bm != null) {
			// 显示内存的图片
			iv.setImageBitmap(bm);
		} else {
			new Thread(new Runnable() {
				@Override
				public void run() {
					// 网络图片下载
					try {
						URL url = new URL(urlPath);
						HttpURLConnection conn = (HttpURLConnection) url
								.openConnection();
						conn.setRequestMethod("GET");
						conn.setConnectTimeout(8000);
						if (conn.getResponseCode() == 200) {
							InputStream is = conn.getInputStream();
							// 下载转换图片的时候可能OOM,进行options的处理
							Bitmap bm = BitmapFactory.decodeStream(is);// 把网上下载字节流转化bitmap
							// 存放到内存缓存中(LruCache的缓存是强引用缓存)
							myLruCache.put(urlPath, bm);
							putBitmap(urlPath, bm);
							// 发送消息(携带数据内容)更新控件
							Message msg = handler.obtainMessage();
							msg.what = 0;
							msg.obj = bm;
							handler.sendMessage(msg);
						}
					} catch (MalformedURLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (ProtocolException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}).start();
		}
	}

	/**
	 * 从内存中读取数据，返回bitmap
	 * 
	 * @param url
	 *            网址
	 * @returnb bitmap 图片
	 */
	private Bitmap getBitmapFromCache(String url) {
		Bitmap bm = myLruCache.get(url);
		if (bm != null) {
			// 从LruCache中获取了数据了
			Log.i("123", "从A缓存(强引用)获取图片");
			return bm;
		} else {
			// 从软引用集合里读取数据
			SoftReference<Bitmap> sortReference = map.get(url);
			if (sortReference != null) {
				// 软引用还存在(获取里面的图片)
				bm = sortReference.get();
				Log.i("123", "从B缓存(入引用)获取图片");
				if (bm != null) {// 图片还是存在
					// 把他存放到myLruCache中
					myLruCache.put(url, bm);
					Log.i("123", "B缓存图片--->A缓存");
					return bm;
				}
				// 从软引用的map中移除
				map.remove(url);
			}
		}
		// 从L3缓存中取数据(读本地图片)

		// 获取缓存文件夹的路径
		Log.i("123", "-----");
		String cachePath = getCachePath();

		// 截取图片名称
		String[] str = url.split("/");
		String imgName = str[str.length - 1];

		File file = new File(cachePath + "/" + imgName);
		if (file.exists()) {

			Bitmap bitmap3 = BitmapFactory
					.decodeFile(cachePath + "/" + imgName);
			if (bitmap3 != null) {
				myLruCache.put(url, bitmap3);// 重新进入一级缓存进行轮回
				return bitmap3;

			}
		}
		return null;
	}

	public String getCachePath() {

		File fileCache = null;
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {

			// 有SD卡，则在SD卡中创建缓存路径
			fileCache = MainActivity.this.getExternalCacheDir();

			Log.i("TAG", "sd=======");
		} else {// 保存图片到手机自带的存储空间中
				// 在手机内部存储中创建缓存文件夹
			fileCache = MainActivity.this.getCacheDir();

			Log.i("TAG", "  no  sd=======");
		}

		// Log.i("TAG", "exist =  " + fileCache.exists());
		Log.i("123", "-----8888--");
		// 保存图片的路径
		String sdCachePath = fileCache.getAbsolutePath();
		return sdCachePath;

	}

	// 接收ImageLoader传递的数据。故可以在该方法中实现缓存代码
	public void putBitmap(String url, Bitmap bitmap) {
		// 把ImageLoader请求的数据存入缓存容器LruCache中
		myLruCache.put(url, bitmap);// L1(一级缓存)

		// 获取缓存路径
		String cachePath = getCachePath();
		// 判定新添加图片之后是否超过预设值，如果超过就删除部分图片
		deleteCacheFile(cachePath, bitmap);
		// 把请求的图片保存在存储介质中(SD卡存储或者手机存储)L3（三级缓存）
		// 截取图片的名字
		String[] str = url.split("/");
		String imgName = str[str.length - 1];

		try {
			FileOutputStream fos = new FileOutputStream(cachePath + "/"
					+ imgName);
			// 把图片写入到本地保存
			bitmap.compress(CompressFormat.JPEG, 100, fos);
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 删除缓存文件
	public void deleteCacheFile(String cachePath, Bitmap bitmap) {
		// 存本地图片的时候判定之前的存储容量(如何大于某个预设值可以删除一些存储的比较久的图片，然后在把新的图片存入)
		File cacheFile = new File(cachePath);
		File[] cacheFileList = cacheFile.listFiles();
		long lenSum = 0;// 存储缓存文件的总容量
		for (File f : cacheFileList) {
			lenSum = lenSum + f.length();
		}

		// 累加上新添加的图片的大小
		int rowByte = bitmap.getRowBytes();// 新图片的行的字节数
		int height = bitmap.getHeight();// 新图片的高度
		int total = rowByte * height;
		lenSum = lenSum + total;

		// 判定总容量是否大于预设值(20M)
		if (lenSum > 20 * 1024 * 1024) {// 删除一些比较早存入的图片
			// 对缓存的文件进行按修改时间的先后进行排序
			Arrays.sort(cacheFileList, new Comparator<File>() {

				@Override
				public int compare(File lhs, File rhs) {
					return (int) (lhs.lastModified() - rhs.lastModified());
				}
			});
			// 删除一部分较早存入的图片(删除整个图片的1/3)
			for (int i = 0; i < cacheFile.length() / 3; i++) {
				cacheFileList[i].delete();
			}
		}
	}

}